package com.example.demo.api;
import com.example.demo.game.MatchRequest;
import com.example.demo.game.MatchResponse;
import com.example.demo.game.Matcher;
import com.example.demo.game.OnlineUserManager;
import com.example.demo.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;


/**
 * @program: gobang
 * @author: JCM
 * @create: 2023-03-09 13:34
 * @description: 处理匹配功能中的 websocket 请求
 **/
@Component
public class MatchAPI extends TextWebSocketHandler {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private OnlineUserManager onlineUserManager;
    @Autowired
    private Matcher matcher;

    public MatchAPI() {
    }


    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 玩家上线，加入到 OnlineUserManager 中

        // 1、先获取到当前用户的身份信息（谁在游戏大厅中，建立的连接）
        // 此处的代码，之所以能够 getAttributes，是因为在注册 WebSocket 的时候加上的
        // .addInterceptors(new HttpSessionHandshakeInterceptor()
        // 这段代码把 HttpSession 中的 Attribute 都拿到了 WebSocketSession 中了
        // 在 Http 登录逻辑中，往HttpSession 中存入了 User 数据：httpSession.setAttribute("user",user);
        // 此时就可以在 WebSocketSession 拿到 User 对象
        // 注意：此处拿到的 user 可能为空
        try {
            User user = (User) session.getAttributes().get("user");

            // 2. 判断当前用户是否已经登录，如果已经登录则不应该再登录
            if(onlineUserManager.getFromGameHall(user.getUserId()) != null
                || onlineUserManager.getFromGameRoom(user.getUserId()) != null) {
                // 当前用户已经登录
                // 针对这个情况要告知客户端
                MatchResponse response = new MatchResponse();
                response.setOk(true);
                response.setReason("当前禁止多开！");
                response.setMessage("repeatConnection");
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
                //session.close();
                return;
            }

            // 3. 拿到身份信息之后，就可以把玩家设置成在线状态
            onlineUserManager.enterGameHall(user.getUserId(),session);
            System.out.println("玩家："+user.getUsername()+" 进入游戏大厅！");

        } catch (NullPointerException e) {
            System.out.println("[MatchAPI.afterConnectionEstablished]当前用户尚未登录");
            //e.printStackTrace();
            // 出现空指针异常，说明当前用户信息为空
            // 把当前用户尚未登录信息返回给服务器
            MatchResponse response = new MatchResponse();
            response.setOk(false);
            response.setReason("用户未登录，请先登录");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 处理开始匹配请求和停止匹配请求
        User user = (User) session.getAttributes().get("user");
        // 获取服务端给服务器发送的信息
        String payload = message.getPayload();
        // 当前数据载荷是一个 JSON 格式的字符串，需要把它转换成 Java 对象，MatchRequest
        MatchRequest request = objectMapper.readValue(payload, MatchRequest.class);
        MatchResponse response = new MatchResponse();
        if (request.getMessage().equals("startMatch")) {
            // 进入匹配队列
            matcher.add(user);
            // 把玩家信息放入匹配队列之后，可以返回一个响应给客户端
            response.setOk(true);
            response.setMessage("startMatch");
        }else if(request.getMessage().equals("stopMatch")) {
            // 退出匹配队列
            matcher.remove(user);
            // 移除之后返回一个响应给客户端
            response.setOk(true);
            response.setMessage("stopMatch");
        }else {
            response.setOk(false);
            response.setMessage("非法的匹配请求");
        }
        String jsonString = objectMapper.writeValueAsString(response);
        session.sendMessage(new TextMessage(jsonString));
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        // 玩家下线，从 OnlineUserManager 中删除
        try {
            User user = (User) session.getAttributes().get("user");
            WebSocketSession tmpSession = onlineUserManager.getFromGameHall(user.getUserId());
            if(tmpSession == session) {
                onlineUserManager.exitGameHall(user.getUserId());
            }
            // 如果玩家正在匹配中，websocket 连接断开
            matcher.remove(user);
        }catch (NullPointerException e) {
            System.out.println("[MatchAPI.handleTransportError]当前用户尚未登录");
//            e.printStackTrace();
//            MatchResponse response = new MatchResponse();
//            response.setOk(false);
//            response.setReason("用户未登录，请先登录");
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }

    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        // 玩家下线，从 OnlineUserManager 中删除
        try {
            User user = (User) session.getAttributes().get("user");
            WebSocketSession tmpSession = onlineUserManager.getFromGameHall(user.getUserId());
            if(tmpSession == session) {
                onlineUserManager.exitGameHall(user.getUserId());
            }
            // 如果玩家正在匹配中，突然关闭了 websocket
            matcher.remove(user);
        }catch (NullPointerException e) {
            System.out.println("[MatchAPI.afterConnectionClosed]当前用户尚未登录");
            // 不应该在连接关闭之后，还尝试给客户端发送消息
//            e.printStackTrace();
//            MatchResponse response = new MatchResponse();
//            response.setOk(false);
//            response.setReason("用户未登录，请先登录");
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }
}
